Skip to content

Recency-sort browse lists; label Claude projects with session title#56

Merged
eliothedeman merged 1 commit intomainfrom
eliot/angry-sinoussi-2f297b
Apr 24, 2026
Merged

Recency-sort browse lists; label Claude projects with session title#56
eliothedeman merged 1 commit intomainfrom
eliot/angry-sinoussi-2f297b

Conversation

@eliothedeman
Copy link
Copy Markdown
Collaborator

Summary

Two related UX improvements to the toolpath-desktop Browse screens:

1. Sort by recency. Claude projects/sessions, Pi projects/sessions, and Git branches previously rendered in backend-emission order — usually alphabetical or directory-walk. Now they're sorted most-recently-active first, matching the convention the tray popover's Recent list already uses (src/tray.rs:87).

2. Label Claude projects with their latest session title. Project rows previously showed the directory basename, which is uninformative for worktrees (2f297b, fa7bdc, c44db4…). Now each project row displays the first-user-message of its most-recent session as the primary title, falling back to the basename while the title loads.

What changed

Backend (crates/toolpath-desktop/src/commands/sources.rs, main.rs)

  • ClaudeProjectQuick gains last_activity: Option<String>, populated by a new newest_jsonl_mtime helper — a cheap directory stat walk (max mtime across the project's .jsonl files), no JSONL parsing. Preserves the original perf intent of the streaming payload.
  • New IPC command claude_project_latest_title(project_path) reads the most-recent session's first user message (via existing ClaudeConvo::title) and returns Option<String>. Registered in the Tauri invoke handler.

Frontend (frontend/src/lib/)

  • byRecencyDesc comparator in update.ts — descending, nulls last, lexicographic on RFC3339.
  • Sort on arrival for every stream handler: ClaudeProjectReceived, ClaudeSessionReceived, PiProjectReceived, PiSessionReceived, GitBranchesLoaded.
  • PiSlice.maxTimestampByProject: Record<string, string> — Pi has no project-level timestamp, so project-list recency is derived frontend-side from streamed session timestamps.
  • ClaudeSlice.projectTitles: Record<string, string> + ClaudeProjectTitleLoaded msg; ClaudeProjectReceived now kicks off the title fetch lazily so project rows paint immediately and titles fill in after.
  • BrowseClaude.svelte renders projectTitles[p.project_path] ?? p.display_name.

Design notes for reviewers

  • The streaming ClaudeProjectQuick payload previously documented last_activity as "deliberately omitted to avoid re-introducing per-session metadata reads." The new stat-based approach respects that intent — we only stat files (no JSON parsing) to get recency. The expensive title read is split into a separate lazy command.
  • Pi project recency uses the frontend-computed max of streamed session timestamps. Projects without sessions yet sit at the bottom until their first session streams in and re-sorts the list. Chosen over adding a backend field to keep the change surface small.
  • Git branches are auto-selected by sortedList[0].name — unchanged semantically from "first in display order is selected" but now "first" means "most recent".

Test plan

  • cargo build -p toolpath-desktop — clean
  • cargo test -p toolpath-desktop — 17/17 pass
  • bun run check in frontend — 0 errors, 0 warnings, 170 files
  • bun run build — 194 modules transformed, clean
  • cargo tauri dev — manual verification:
    • Browse → Claude Code: projects ordered most-recently-active first; worktree project rows show a conversation title instead of 2f297b-style basenames; expanded sessions ordered newest-first.
    • Browse → pi.dev: sessions within each project newest-first; after sessions stream in, projects reorder so the ones with the newest session float to the top.
    • Browse → Local git: load a repo with multiple branches; branches ordered by tip-commit timestamp desc; newest branch auto-selected.
    • Compare tray popover's Recent list with Browse lists — same provider's top row should match.

…cts with session title

Browse lists (Claude projects/sessions, Pi projects/sessions, Git branches)
previously rendered in backend emission order — usually alphabetical or
directory-walk. Now they sort most-recently-active first, matching the
convention already used by the tray popover's Recent list.

For Claude projects specifically, the streaming payload deliberately skipped
last_activity to avoid per-session JSONL parsing; adds a cheap stat-based
hint (max mtime across the project's .jsonl files).

Pi projects have no project-level timestamp, so recency is derived
frontend-side from the streamed session timestamps via a
maxTimestampByProject map.

Also replaces the opaque worktree-basename project titles (e.g. "2f297b",
"fa7bdc") with the first-user-message of each project's most-recent session,
via a new `claude_project_latest_title` IPC command fetched lazily per
project. Falls back to the basename while the title loads or if the
conversation has no user text.
@github-actions
Copy link
Copy Markdown

🔍 Preview deployed: https://46f398e4.toolpath.pages.dev

@eliothedeman eliothedeman merged commit d765b16 into main Apr 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant